package thesis.filesharing.web.controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import thesis.filesharing.bo.ClassBO;
import thesis.filesharing.bo.SemesterBO;
import thesis.filesharing.bo.StudentBO;
import thesis.filesharing.common.exception.functional.InvalidArgumentException;
import thesis.filesharing.common.util.Utils;
import thesis.filesharing.common.util.XMLUtil;
import thesis.filesharing.common.valueobjects.SearchClassValueObject;
import thesis.filesharing.common.valueobjects.SearchStudentValueObject;
import thesis.filesharing.model.Clazz;
import thesis.filesharing.model.Student;
import thesis.filesharing.resources.Constants;
import thesis.filesharing.services.fulltextsearch.indexing.DocumentIndexing;
import thesis.filesharing.services.fulltextsearch.indexing.DocumentQuery;
import thesis.filesharing.services.fulltextsearch.indexing.Operators;
import thesis.filesharing.services.fulltextsearch.indexing.QueryBuilder;
import thesis.filesharing.web.auth.AuthUtil;
import thesis.filesharing.web.auth.Roles;
import thesis.filesharing.web.util.PageInfo;
import thesis.filesharing.web.util.PropertiesUtil;
import thesis.filesharing.web.util.Util;
import thesis.filesharing.web.validator.CreateStudentValidator;
import thesis.filesharing.web.validator.StudentChangePasswordValidator;
import thesis.filesharing.web.validator.UpdateStudentInfoValidator;
import thesis.filesharing.web.validator.UpdateStudentValidator;
import thesis.filesharing.web.viewmodel.ChangePasswordViewModel;
import thesis.filesharing.web.viewmodel.CreateStudentViewModel;
import thesis.filesharing.web.viewmodel.UpdateStudentInfoViewModel;
import thesis.filesharing.web.viewmodel.UpdateStudentViewModel;
import thesis.filesharing.web.viewmodel.ajaxbeans.StudentBean;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.search.Field;
import com.google.appengine.api.search.Results;
import com.google.appengine.api.search.ScoredDocument;

@Controller
public class StudentController {
	
	@Autowired
	private UpdateStudentValidator updateStudentValidator;
	
	@Autowired
	private CreateStudentValidator createStudentValidator;
	
	@Autowired
	private UpdateStudentInfoValidator updateStudentInfoValidator;
	
	@Autowired
	private StudentChangePasswordValidator studentChangePasswordValidator;
	
	@Autowired
	private StudentBO studentBO;
	
	@Autowired
	private ClassBO classBO;
	
	@Autowired
	private SemesterBO semesterBO;
	
	List<String> classNames = XMLUtil.readDataNodes(Constants.DEPARTMENTS_FILE_PATH, "department-name");
	List<String> courseNames = XMLUtil.readDataNodes(Constants.COURSES_FILE_PATH, "course");
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value = "/admin/listStudents", method = RequestMethod.GET)
	public String listStudents(@RequestParam(value = "p", required = false, defaultValue = "1") Integer p, ModelMap model) {
		if (p < 1 || p > Util.calculateNumberOfPage(studentBO.countStudents(), Constants.PAGE_SIZE)) {
			p = 1;
		}
		
		List<Student> students = studentBO.listStudents(p, Constants.PAGE_SIZE);
		model.addAttribute("students", students);
		model.addAttribute("pageInfo", new PageInfo(studentBO.countStudents(), p));
		model.addAttribute("pageSize", Constants.PAGE_SIZE);
		model.addAttribute("classNames", classNames);
		model.addAttribute("courseNames", courseNames);
		return "admin/listStudents";
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value = "/admin/deleteStudent/{key}", method = RequestMethod.GET)
	public RedirectView deleteStudent(@PathVariable("key") String key, 
			@RequestParam(value = "p", required = false, defaultValue = "1") Integer p,
			ModelMap model, HttpSession session, HttpServletRequest request) {
		if (p < 1 || p > Util.calculateNumberOfPage(studentBO.countStudents(), Constants.PAGE_SIZE)) {
			p = 1;
		}
		
		int totalItems = 0;
		int newPage = 1;
		
		if (request.getParameter("sId") == null) {
			totalItems = studentBO.countStudents();
		} else {
			totalItems = studentBO.countFoundStudents(buildSearchObject(request));
		}
		
		studentBO.deleteStudent(key);
		DocumentIndexing.removeEntityIndex(key, Constants.SEARCH_INDEX_NAME);
		newPage = Util.evaluatePageNumAfterDelete(p, totalItems, Constants.PAGE_SIZE, 1);
		session.setAttribute("msg", PropertiesUtil.getProperty("student.delete.success"));
		
		if (request.getParameter("sId") == null) {
			return new RedirectView("/admin/listStudents.html?p=" + newPage);
		} else {
			Map<String, String> modifiedParams = new HashMap<String, String>();
			modifiedParams.put("p", String.valueOf(newPage));
			return new RedirectView("/admin/searchStudents.html?" + Util.modifyQueryString(request, modifiedParams));
		}
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value = "/admin/deleteStudents", method = RequestMethod.POST)
	public RedirectView deleteStudents(@RequestParam(value = "p", required = false, defaultValue = "1") Integer p,
			ModelMap model, HttpServletRequest request, HttpSession session) {
		if (p < 1 || p > Util.calculateNumberOfPage(studentBO.countStudents(), Constants.PAGE_SIZE)) {
			p = 1;
		}
		
		String[] studentKeys = request.getParameterValues("checkItem");
		int newPage = 1;
		int totalItems = 0;
		
		if (request.getParameter("sId") == null) {
			totalItems = studentBO.countStudents();
		} else {
			totalItems = studentBO.countFoundStudents(buildSearchObject(request));
		}
		
		if (studentKeys != null && studentKeys.length > 0) {
			for (String k : studentKeys) {
				studentBO.deleteStudent(k);
			}
			newPage = Util.evaluatePageNumAfterDelete(p, totalItems, Constants.PAGE_SIZE, studentKeys.length);
		}
		DocumentIndexing.removeEntityIndexes(new ArrayList<String>(Arrays.asList(studentKeys)), Constants.SEARCH_INDEX_NAME);
		session.setAttribute("msg", PropertiesUtil.getProperty("student.delete.success"));
		
		if (request.getParameter("sId") == null) {
			return new RedirectView("/admin/listStudents.html?p=" + newPage);
		} else {
			Map<String, String> modifiedParams = new HashMap<String, String>();
			modifiedParams.put("p", String.valueOf(newPage));
			return new RedirectView("/admin/searchStudents.html?" + Util.modifyQueryString(request, modifiedParams));
		}
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value = "/admin/updateStudent/{key}", method = RequestMethod.GET)
	public String initUpdateStudentForm(@PathVariable("key") String key, ModelMap model) {
		UpdateStudentViewModel updateStudentViewModel = new UpdateStudentViewModel();
		Student student = studentBO.findStudentByKey(KeyFactory.stringToKey(key));
		if (student != null) {
			updateStudentViewModel.setStudentKey(KeyFactory.keyToString(student.getStudentKey()));
			updateStudentViewModel.setStudentId(student.getStudentId());
			updateStudentViewModel.setStudentName(student.getStudentName());
			updateStudentViewModel.setStudentEmail(student.getStudentEmail());
			updateStudentViewModel.setClassName(String.valueOf(classNames.indexOf(student.getClassName())));
			updateStudentViewModel.setCourse(String.valueOf(courseNames.indexOf(String.valueOf(student.getCourse()))));
			updateStudentViewModel.setActive(student.isActive());
		}
		model.addAttribute("updateStudentViewModel", updateStudentViewModel);
		return "admin/updateStudent";
	}
	
	@ModelAttribute("classes")
	public Map<Integer, String> populateClasses() {
		Map<Integer, String> classes = new LinkedHashMap<Integer, String>();
		for (int i = 0; i < classNames.size(); i++) {
			classes.put(i, classNames.get(i));
		}
		return classes;
	}
	
	@ModelAttribute("courses")
	public Map<Integer, Integer> populateCourses() {
		Map<Integer, Integer> courses = new LinkedHashMap<Integer, Integer>();
		for (int i = 0; i < courseNames.size(); i++) {
			courses.put(i, Integer.parseInt(courseNames.get(i)));
		}
		return courses;
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value = "/admin/updateStudent/{key}", method = RequestMethod.POST)
	public ModelAndView processUpdateStudentSubmit(
			@ModelAttribute("updateStudentViewModel") UpdateStudentViewModel updateStudentViewModel,
			@RequestParam(value = "p", required = false, defaultValue = "1") Integer p,
			BindingResult bindingResult, SessionStatus status, ModelMap model, HttpSession session, HttpServletRequest request) {
		
		updateStudentValidator.validate(updateStudentViewModel, bindingResult);
		
		if (bindingResult.hasErrors()) {
			return new ModelAndView("admin/updateStudent");
		} else {
			status.setComplete();
			
			String className = classNames.get(Integer.parseInt(updateStudentViewModel.getClassName()));
			Integer courseName = Integer.parseInt(courseNames.get(Integer.parseInt(updateStudentViewModel.getCourse())));
			Set<String> roles = new HashSet<String>();
			roles.add(Roles.ROLE_STUDENT.getRole());
			
			Student student = studentBO.findStudentByKey(KeyFactory.stringToKey(updateStudentViewModel.getStudentKey()));
			Student s = new Student(student.getStudentKey(), student.getStudentId(), updateStudentViewModel.getStudentName(), 
					updateStudentViewModel.getStudentEmail(), className, courseName, student.getStudentPassword(), 
					updateStudentViewModel.getActive(), roles);
			s = studentBO.updateStudent(s);
			DocumentIndexing.addEntityIndex(s, Constants.SEARCH_INDEX_NAME);
			
			session.setAttribute("msg", PropertiesUtil.getProperty("student.update.success"));
			if (request.getParameter("sId") == null) {
				return new ModelAndView(new RedirectView("/admin/listStudents.html?p=" + p));
			} else {
				String queryString = request.getQueryString();
				return new ModelAndView(new RedirectView("/admin/searchStudents.html?" + queryString));
			}
		}
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/changePassword", method = RequestMethod.GET)
	public String initChangePasswordForm(ModelMap model) {
		ChangePasswordViewModel changePasswordViewModel = new ChangePasswordViewModel();
		model.addAttribute("changePasswordViewModel", changePasswordViewModel);
		return "student/changePassword";
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/changePassword", method = RequestMethod.POST)
	public ModelAndView processChangePasswordSubmit(
			@ModelAttribute("changePasswordViewModel") ChangePasswordViewModel changePasswordViewModel,
			BindingResult bindingResult, SessionStatus status, HttpSession session) {
		
		studentChangePasswordValidator.validate(changePasswordViewModel, bindingResult);
		
		if (bindingResult.hasErrors()) {
			return new ModelAndView("student/changePassword");
		} else {
			status.setComplete();
			
			Student s = studentBO.findStudentById(AuthUtil.getCurrentAuthenticatedUsername());
			if (s != null) {
				Student student = new Student(s.getStudentKey(), s.getStudentId(), s.getStudentName(), s.getStudentEmail(), 
						s.getClassName(), s.getCourse(), changePasswordViewModel.getNewPassword(), s.isActive(), s.getRoles());
				studentBO.updateStudent(student);
				session.setAttribute("msg", PropertiesUtil.getProperty("student.changePassword.success"));
			} else {
				session.setAttribute("msg", PropertiesUtil.getProperty("student.changePassword.failure"));
			}
			return new ModelAndView(new RedirectView("/student/changePassword.html"));
		}
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value = "/admin/createStudent", method = RequestMethod.GET)
	public String initCreateStudentForm(ModelMap model) {
		CreateStudentViewModel createStudentViewModel = new CreateStudentViewModel();
		model.addAttribute("createStudentViewModel", createStudentViewModel);
		return "admin/createStudent";
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value = "/admin/createStudent", method = RequestMethod.POST)
	public ModelAndView processCreateStudentSubmit(
			@ModelAttribute("createStudentViewModel") CreateStudentViewModel createStudentViewModel,
			BindingResult bindingResult, SessionStatus status, ModelMap model, HttpSession session) {
		createStudentValidator.validate(createStudentViewModel, bindingResult);
		if (bindingResult.hasErrors()) {
			return new ModelAndView("admin/createStudent");
		} else {
			status.setComplete();
			
			String className = classNames.get(Integer.parseInt(createStudentViewModel.getClassName()));
			Integer courseName = Integer.parseInt(courseNames.get(Integer.parseInt(createStudentViewModel.getCourse()))); 
			Student student = new Student(createStudentViewModel.getStudentId(), createStudentViewModel.getStudentName(), 
					createStudentViewModel.getStudentEmail(), className, courseName, Util.generatePassword(), createStudentViewModel.getActive(), 
					new HashSet<String>(Arrays.asList(Roles.ROLE_STUDENT.getRole())));
			student = studentBO.saveStudent(student);
			DocumentIndexing.addEntityIndex(student, Constants.SEARCH_INDEX_NAME);
			// Code for sending mail goes here
			session.setAttribute("msg", PropertiesUtil.getProperty("student.create.success"));
			return new ModelAndView(new RedirectView("/admin/listStudents.html"));
		}
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value = "/admin/searchStudents", method = RequestMethod.GET)
	public String searchStudent(@RequestParam(value = "sId", required = false, defaultValue = "") String studentId,
			@RequestParam(value = "sName", required = false, defaultValue = "") String studentName,
			@RequestParam(value = "sEmail", required = false, defaultValue = "") String studentEmail,
			@RequestParam(value = "cl", required = false, defaultValue = "-1") Integer className,
			@RequestParam(value = "co", required = false, defaultValue = "-1") Integer course,
			@RequestParam(value = "active", required = false, defaultValue = "false") Boolean active,
			@RequestParam(value = "p", required = false, defaultValue = "1") Integer p,
			ModelMap model) {
		
		SearchStudentValueObject searchObj = new SearchStudentValueObject();
		Map<String, String> params = new HashMap<String, String>();
		
		if (studentId != null && !"".equals(studentId)) {
			searchObj.setStudentId(studentId);
			params.put("sId", studentId);
		}
		if (studentName != null && !"".equals(studentName)) {
			searchObj.setStudentName(studentName);
			params.put("sName", studentName);
		}
		if (studentEmail != null && !"".equals(studentEmail)) {
			searchObj.setStudentEmail(studentEmail);
			params.put("sEmail", studentEmail);
		}
		if (className != null && className >= 0 && className < classNames.size()) {
			searchObj.setClassName(classNames.get(className));
			params.put("cl", String.valueOf(className));
		}
		if (course != null && course >= 0 && course < courseNames.size()) {
			searchObj.setCourse(Integer.parseInt(courseNames.get(course)));
			params.put("co", String.valueOf(course));
		}
		if (active != null) {
			searchObj.setActive(active);
			params.put("active", String.valueOf(active));
		}
		
		model.addAttribute("students", studentBO.searchStudent(searchObj, p, Constants.PAGE_SIZE));
		model.addAttribute("pageInfo", new PageInfo(studentBO.countFoundStudents(searchObj), p));
		model.addAttribute("pageSize", Constants.PAGE_SIZE);
		model.addAttribute("classNames", classNames);
		model.addAttribute("courseNames", courseNames);
		model.addAttribute("params", params);
		
		return "admin/searchStudents";
	}
	
	private SearchStudentValueObject buildSearchObject(HttpServletRequest request) {
		String studentId = request.getParameter("sId");
		String studentName = request.getParameter("sName");
		String studentEmail = request.getParameter("sEmail");
		String className = request.getParameter("cl");
		String course = request.getParameter("co");
		String active = request.getParameter("active");
		
		SearchStudentValueObject searchObj = new SearchStudentValueObject();
		
		try {
			if (studentId != null && !"".equals(studentId)) {
				searchObj.setStudentId(studentId);
			}
			if (studentName != null && !"".equals(studentName)) {
				searchObj.setStudentName(studentName);
			}
			if (studentEmail != null && !"".equals(studentEmail)) {
				searchObj.setStudentEmail(studentEmail);
			}
			if (className != null && !"".equals(className) && Integer.parseInt(className) >= 0 && Integer.parseInt(className) < classNames.size()) {
				searchObj.setClassName(classNames.get(Integer.parseInt(className)));
			}
			if (course != null && !"".equals(course) && Integer.parseInt(course) >= 0 && Integer.parseInt(course) < courseNames.size()) {
				searchObj.setCourse(Integer.parseInt(courseNames.get(Integer.parseInt(course))));
			}
			if (active != null) {
				searchObj.setActive(Boolean.parseBoolean(active));
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			throw new InvalidArgumentException(ex);
		}
		
		return searchObj;
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/info", method = RequestMethod.GET)
	public String initUpdateStudentInfoForm(ModelMap model) {
		UpdateStudentInfoViewModel updateStudentInfoViewModel = new UpdateStudentInfoViewModel();
		String currentStudentId = AuthUtil.getCurrentAuthenticatedUsername();
		if (currentStudentId != null) {
			Student student = studentBO.findStudentById(currentStudentId);
			if (student != null) {
				updateStudentInfoViewModel.setStudentKey(KeyFactory.keyToString(student.getStudentKey()));
				updateStudentInfoViewModel.setStudentId(student.getStudentId());
				updateStudentInfoViewModel.setStudentName(student.getStudentName());
				updateStudentInfoViewModel.setStudentEmail(student.getStudentEmail());
				updateStudentInfoViewModel.setClassName(String.valueOf(classNames.indexOf(student.getClassName())));
				updateStudentInfoViewModel.setCourse(String.valueOf(courseNames.indexOf(String.valueOf(student.getCourse()))));
			}
		}
		model.addAttribute("updateStudentInfoViewModel", updateStudentInfoViewModel);
		return "student/info";
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/info", method = RequestMethod.POST)
	public ModelAndView processUpdateStudentInfoSubmit(
			@ModelAttribute("updateStudentInfoViewModel") UpdateStudentInfoViewModel updateStudentInfoViewModel,
			@RequestParam(value = "p", required = false, defaultValue = "1") Integer p,
			BindingResult bindingResult, SessionStatus status, ModelMap model, HttpSession session, HttpServletRequest request) {
		
		updateStudentInfoValidator.validate(updateStudentInfoViewModel, bindingResult);
		
		if (bindingResult.hasErrors()) {
			return new ModelAndView("student/info");
		} else {
			status.setComplete();
			
			String className = classNames.get(Integer.parseInt(updateStudentInfoViewModel.getClassName()));
			Integer courseName = Integer.parseInt(courseNames.get(Integer.parseInt(updateStudentInfoViewModel.getCourse())));
			Set<String> roles = new HashSet<String>();
			roles.add(Roles.ROLE_STUDENT.getRole());
			
			Student student = studentBO.findStudentByKey(KeyFactory.stringToKey(updateStudentInfoViewModel.getStudentKey()));
			Student s = new Student(student.getStudentKey(), student.getStudentId(), updateStudentInfoViewModel.getStudentName(), 
					updateStudentInfoViewModel.getStudentEmail(), className, courseName, student.getStudentPassword(), 
					student.isActive(), roles);
			s = studentBO.updateStudent(s);
			DocumentIndexing.addEntityIndex(s, Constants.SEARCH_INDEX_NAME);
			
			session.setAttribute("msg", PropertiesUtil.getProperty("student.update.success"));
			return new ModelAndView(new RedirectView("/student/info.html"));
		}
	}
	
	@PreAuthorize("hasRole('ROLE_LECTURER')")
	@RequestMapping(value = "/lecturer/listStudentsInClass", method = RequestMethod.GET)
	public String listStudentsInClass(@RequestParam(value = "p", required = false, defaultValue = "1") Integer p, 
			@RequestParam(value = "key", required = false) String key, ModelMap model) {
		if (key != null && key.length() > 0 && !"NONE".equals(key)) {
			int totalStudents = studentBO.countStudentsInClass(key);
			if ( p < 1 || p > Util.calculateNumberOfPage(totalStudents, Constants.PAGE_SIZE)) {
				p = 1;
			}
			
			model.addAttribute("students", studentBO.listStudentsInClass(key, p, Constants.PAGE_SIZE));
			model.addAttribute("pageInfo", new PageInfo(totalStudents, p));
			model.addAttribute("pageSize", Constants.PAGE_SIZE);
			model.addAttribute("currentClass", classBO.findClassByKey(key));
			Map<String, String> params = new HashMap<String, String>();
			params.put("key", key);
			model.addAttribute("params", params);
		}
		String lecturerId = AuthUtil.getCurrentAuthenticatedUsername();
		List<Clazz> classes = classBO.searchClasses(new SearchClassValueObject(null, null, lecturerId, semesterBO.getCurrentSemester().getSemesterName()));
		model.addAttribute("classes", classes);
		
		return "lecturer/listStudentsInClass";
	}
	
	@PreAuthorize("hasRole('ROLE_LECTURER')")
	@RequestMapping(value = "/lecturer/deleteStudentInClass/{studentKey}", method = RequestMethod.GET)
	public RedirectView deleteStudentFromClass(@PathVariable("studentKey") String studentKey, 
			@RequestParam(value = "p", required = false, defaultValue = "1") Integer p,  
			@RequestParam(value = "key", required = false) String classKey, HttpSession session) {
		
		int totalItems = studentBO.countStudentsInClass(classKey);
		if (p < 1 || p > Util.calculateNumberOfPage(totalItems, Constants.PAGE_SIZE)) {
			p = 1;
		}
		
		classBO.deleteStudentFromClass(studentKey, classKey);
		int newPage = Util.evaluatePageNumAfterDelete(p, totalItems, Constants.PAGE_SIZE, 1);
		session.setAttribute("msg", PropertiesUtil.getProperty("studentInClass.delete.success"));
		
		return new RedirectView("/lecturer/listStudentsInClass.html?p=" + newPage + "&key=" + classKey);
	}
	
	@PreAuthorize("hasRole('ROLE_LECTURER')")
	@RequestMapping(value = "/lecturer/deleteStudentsInClass", method = RequestMethod.POST)
	public RedirectView deleteStudentsFromClass(@RequestParam(value = "p", required = false, defaultValue = "1") Integer p,
			@RequestParam(value="key", required = false, defaultValue = "1") String classKey, HttpSession session, 
			HttpServletRequest request) {
		
		int totalItems = studentBO.countStudentsInClass(classKey);
		if (p < 1 || p > Util.calculateNumberOfPage(totalItems, Constants.PAGE_SIZE)) {
			p = 1;
		}
		
		int newPage = 1;
		String[] studentKeys = request.getParameterValues("checkItem");
		if (studentKeys != null && studentKeys.length > 0) {
			for (String k : studentKeys) {
				classBO.deleteStudentFromClass(k, classKey);
			}
			newPage = Util.evaluatePageNumAfterDelete(p, totalItems, Constants.PAGE_SIZE, studentKeys.length);
			session.setAttribute("msg", PropertiesUtil.getProperty("studentInClass.delete.success"));
		}
		
		return new RedirectView("/lecturer/listStudentsInClass.html?p=" + newPage + "&key=" + classKey);
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/listClassesStudentRegistered", method = RequestMethod.GET)
	public String listClassesStudentRegistered(ModelMap model) {
		String studentId = AuthUtil.getCurrentAuthenticatedUsername();
		if (studentId != null) {
			model.addAttribute("registeredClasses", studentBO.listClassesStudentRegistered(studentId, semesterBO.getCurrentSemester().getSemesterName()));
		}
		
		return "student/listClassesStudentRegistered";
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/searchStudentsInClassAjax", method = RequestMethod.GET)
	public void searchStudentsInClassAjax(
			@RequestParam(value = "q", required = true) String q,
			@RequestParam(value = "classKey", required = false) String classKey,
			HttpServletResponse response) throws IOException {
		response.setContentType("application/json");
		PrintWriter out = response.getWriter();
		q = Utils.insertSignChar(Utils.filterVietnameseSign(q));
		if (q.trim().length() > 0) {
			QueryBuilder builder = new QueryBuilder();
			String query = builder.add("fStudentId", q, Operators.COLON)
					.or("fStudentName", q, Operators.COLON)
					.buildQuery();
			
			Results<ScoredDocument> results = DocumentQuery.search(query, Constants.SEARCH_INDEX_NAME);
			List<StudentBean> studentBeans = new ArrayList<StudentBean>();
			
			Set<Key> studentKeys = null;
			if (classKey != null && !"".equals(classKey)) {
				Clazz c = classBO.findClassByKey(classKey);
				if (c != null) {
					studentKeys = c.getStudentKeys();
				}
			}
			
			for (ScoredDocument result : results) {
				Iterator<Field> fields = result.getFields().iterator();
				
				if (studentKeys == null || (studentKeys != null && studentKeys.contains(KeyFactory.stringToKey(result.getId())))) {
					Field f = null;
					String fieldName = null;
					StudentBean studentBean = new StudentBean();
					studentBean.setStudentKey(result.getId());
					
					while (fields.hasNext()) {
						f = fields.next();
						fieldName = f.getName();
						
						if ("studentId".equals(fieldName)) {
							studentBean.setStudentId(f.getText());
						} else if ("studentName".equals(fieldName)) {
							studentBean.setStudentName(f.getText());
						} else if ("className".equals(fieldName)) {
							studentBean.setClassName(f.getText());
						} else if ("course".equals(fieldName)) {
							studentBean.setCourse(Integer.parseInt(f.getText()));
						}
					}
					studentBeans.add(studentBean);
				}
			}
			
			ObjectMapper mapper = new ObjectMapper();
			out.print(mapper.writeValueAsString(studentBeans));
		} else {
			out.print("[]");
		}
	}
}
